﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using Transfer.Utils;

namespace ShowGridNumber
{
	public class GridNumberShowManager
	{
		public GridNumberShowManager(UIDocument uiDoc)
		{
			this.m_uiDoc = uiDoc;
			this.m_doc = uiDoc.Document;
		}

		public void RefreshUIDocument(UIDocument uiDoc)
		{
			this.m_uiDoc = uiDoc;
			this.m_doc = uiDoc.Document;
			this.m_uiView = null;
			this.m_lstViewOutLineInfo.Clear();
			this.m_lstDrawElems.Clear();
			this.m_lstGridNumShowInfo.Clear();
		}

		private void GetAllRevitLinkInstancesInDoc()
		{
			this.m_lstLinkInst.Clear();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc).OfClass(typeof(RevitLinkInstance));
			ICollection<ElementId> collection = filteredElementCollector.ToElementIds();
			foreach (ElementId elementId in collection)
			{
				Element element = this.m_doc.GetElement(elementId);
				if (!(element.GetType() != typeof(RevitLinkInstance)))
				{
					RevitLinkInstance revitLinkInstance = element as RevitLinkInstance;
					if (revitLinkInstance != null)
					{
						this.m_lstLinkInst.Add(revitLinkInstance);
					}
				}
			}
		}

        public CalcGridInfoResult GetGridNumberShowInfo(bool bIdling, DllImportManeger.Rect rcMDIClientWin, ref System.Drawing.Point ptForm, ref Size sizeForm)
		{
			if (this.m_uiDoc == null)
			{
				return CalcGridInfoResult.eError;
			}
			if (this.m_uiView == null)
			{
				IList<UIView> openUIViews = this.m_uiDoc.GetOpenUIViews();
				foreach (UIView uiview in openUIViews)
				{
					if (uiview.ViewId == this.m_uiDoc.ActiveView.Id)
					{
						this.m_uiView = uiview;
						break;
					}
				}
			}
			if (this.m_uiView == null)
			{
				return CalcGridInfoResult.eError;
			}
			this.GetAllRevitLinkInstancesInDoc();
			this.m_lstViewOutLineInfo.Clear();
			this.m_lstDrawElems.Clear();
			this.m_lstGridNumShowInfo.Clear();
			CalcGridInfoResult currentViewOutLine = this.GetCurrentViewOutLine(bIdling, rcMDIClientWin, ref sizeForm, ref ptForm);
			if (currentViewOutLine != CalcGridInfoResult.eSucceded)
			{
				return currentViewOutLine;
			}
			this.GetAllGridInfo();
			if (this.m_bShowLink)
			{
				this.GetAllGridInfoInLinkDoc();
			}
			this.GetAllMultiSegmentGridInfo();
			if (this.m_bShowLink)
			{
				this.GetAllMultiSegmentGridInfoInLinkDoc();
			}
			this.GetAllLevelInfo();
			if (this.m_lstDrawElems.Count <= 0)
			{
				return CalcGridInfoResult.eError;
			}
			this.GetIntersectPtAndDirection();
			if (this.m_lstGridNumShowInfo.Count <= 0)
			{
				return CalcGridInfoResult.eError;
			}
			return CalcGridInfoResult.eSucceded;
		}

        private CalcGridInfoResult GetCurrentViewOutLine(bool bIdling, DllImportManeger.Rect rcMDIClientWin, ref Size szForm, ref System.Drawing.Point ptForm)
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			RevitViewExtension.GetRevitWndRectangle(this.m_uiView, ref num, ref num3, ref num2, ref num4);
			if (Geometry.IsEqual((double)num, (double)num2) || Geometry.IsEqual((double)num3, (double)num4))
			{
				return CalcGridInfoResult.eMin;
			}
			if (bIdling && Geometry.IsEqual((double)num, (double)this.m_nLeft) && Geometry.IsEqual((double)num3, (double)this.m_nTop) && Geometry.IsEqual((double)num2, (double)this.m_nRight) && Geometry.IsEqual((double)num4, (double)this.m_nBottom))
			{
				return CalcGridInfoResult.eIdling;
			}
			this.m_nLeft = num;
			this.m_nRight = num2;
			this.m_nTop = num3;
			this.m_nBottom = num4;
			if (Geometry.GreaterThan((double)rcMDIClientWin.left, (double)num))
			{
				num = rcMDIClientWin.left;
			}
			if (Geometry.LessThan((double)rcMDIClientWin.right, (double)num2))
			{
				num2 = rcMDIClientWin.right;
			}
			if (Geometry.GreaterThan((double)rcMDIClientWin.top, (double)num3))
			{
				num3 = rcMDIClientWin.top;
			}
			if (Geometry.LessThan((double)rcMDIClientWin.bottom, (double)num4))
			{
				num4 = rcMDIClientWin.bottom;
			}
			XYZ xyz = new XYZ((double)num, (double)num4, 0.0);
			XYZ xyz2 = new XYZ((double)num, (double)num3, 0.0);
			XYZ xyz3 = new XYZ((double)num2, (double)num3, 0.0);
			XYZ xyz4 = new XYZ((double)num2, (double)num4, 0.0);
			szForm.Width = num2 - num;
			szForm.Height = num4 - num3;
			ptForm.X = num;
			ptForm.Y = num3;
			Line lnViewOutline = Line.CreateBound(xyz4, xyz);
			ViewOutLineInfo item = new ViewOutLineInfo(lnViewOutline, OutLineSide.eBottom);
			this.m_lstViewOutLineInfo.Add(item);
			Line lnViewOutline2 = Line.CreateBound(xyz, xyz2);
			ViewOutLineInfo item2 = new ViewOutLineInfo(lnViewOutline2, OutLineSide.eLeft);
			this.m_lstViewOutLineInfo.Add(item2);
			Line lnViewOutline3 = Line.CreateBound(xyz2, xyz3);
			ViewOutLineInfo item3 = new ViewOutLineInfo(lnViewOutline3, OutLineSide.eUp);
			this.m_lstViewOutLineInfo.Add(item3);
			Line lnViewOutline4 = Line.CreateBound(xyz3, xyz4);
			ViewOutLineInfo item4 = new ViewOutLineInfo(lnViewOutline4, OutLineSide.eRight);
			this.m_lstViewOutLineInfo.Add(item4);
			return CalcGridInfoResult.eSucceded;
		}

		private void GetAllGridInfo()
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc, this.m_uiDoc.ActiveView.Id);
			filteredElementCollector.OfClass(typeof(Grid));
			foreach (Element element in filteredElementCollector)
			{
				Grid grid = element as Grid;
				if (grid != null)
				{
					DrawElement item = new DrawElement(grid, ElemType.eGrid, false, grid.Curve);
					this.m_lstDrawElems.Add(item);
				}
			}
		}

		private void GetAllGridInfoInLinkDoc()
		{
			Transform transform = this.m_doc.ActiveView.CropBox.Transform;
			foreach (RevitLinkInstance revitLinkInstance in this.m_lstLinkInst)
			{
				Document linkDocument = revitLinkInstance.GetLinkDocument();
                if (linkDocument != null && (int)this.m_doc.ActiveView.ViewType != 117)
				{
					try
					{
						Transform transform2 = revitLinkInstance.GetTransform();
						Transform transform3 = transform2.Multiply(transform);
						FilteredElementCollector filteredElementCollector = new FilteredElementCollector(linkDocument);
						IList<Element> list = filteredElementCollector.OfClass(typeof(Grid)).ToElements();
						foreach (Element element in list)
						{
							Grid grid = element as Grid;
							if (grid != null)
							{
								DrawElement item;
								if (grid.Curve is Line)
								{
									XYZ xyz = grid.Curve.GetEndPoint(0);
									XYZ xyz2 = grid.Curve.GetEndPoint(1);
									xyz = transform3.OfPoint(xyz);
									xyz2 = transform3.OfPoint(xyz2);
									Line cvGrid = Line.CreateBound(xyz, xyz2);
									item = new DrawElement(grid, ElemType.eGrid, true, cvGrid);
								}
								else
								{
									XYZ xyz3 = grid.Curve.GetEndPoint(0);
									XYZ xyz4 = grid.Curve.GetEndPoint(1);
									XYZ xyz5 = grid.Curve.Evaluate(0.5, true);
									xyz3 = transform3.OfPoint(xyz3);
									xyz4 = transform3.OfPoint(xyz4);
									xyz5 = transform3.OfPoint(xyz5);
									Arc cvGrid2 = Arc.Create(xyz3, xyz4, xyz5);
									item = new DrawElement(grid, ElemType.eGrid, true, cvGrid2);
								}
								this.m_lstDrawElems.Add(item);
							}
						}
					}
					catch (Exception)
					{
					}
				}
			}
		}

		private void GetAllMultiSegmentGridInfo()
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc, this.m_uiDoc.ActiveView.Id);
			filteredElementCollector.OfClass(typeof(MultiSegmentGrid));
			foreach (Element element in filteredElementCollector)
			{
				MultiSegmentGrid multiSegmentGrid = element as MultiSegmentGrid;
				if (multiSegmentGrid != null)
				{
					ICollection<ElementId> gridIds = multiSegmentGrid.GetGridIds();
					foreach (ElementId elementId in gridIds)
					{
						Grid grid = this.m_doc.GetElement(elementId) as Grid;
						if (grid != null)
						{
							DrawElement item = new DrawElement(grid, ElemType.eMultiSegGrid, false, grid.Curve);
							this.m_lstDrawElems.Add(item);
						}
					}
				}
			}
		}

		private void GetAllMultiSegmentGridInfoInLinkDoc()
		{
			Transform transform = this.m_doc.ActiveView.CropBox.Transform;
			foreach (RevitLinkInstance revitLinkInstance in this.m_lstLinkInst)
			{
				Document linkDocument = revitLinkInstance.GetLinkDocument();
                if (linkDocument != null && (int)this.m_doc.ActiveView.ViewType != 117)
				{
					try
					{
						Transform transform2 = revitLinkInstance.GetTransform();
						Transform transform3 = transform2.Multiply(transform);
						FilteredElementCollector filteredElementCollector = new FilteredElementCollector(linkDocument);
						filteredElementCollector.OfClass(typeof(MultiSegmentGrid));
						foreach (Element element in filteredElementCollector)
						{
							MultiSegmentGrid multiSegmentGrid = element as MultiSegmentGrid;
							if (multiSegmentGrid != null)
							{
								ICollection<ElementId> gridIds = multiSegmentGrid.GetGridIds();
								foreach (ElementId elementId in gridIds)
								{
									Grid grid = this.m_doc.GetElement(elementId) as Grid;
									if (grid != null)
									{
										DrawElement item;
										if (grid.Curve is Line)
										{
											XYZ xyz = grid.Curve.GetEndPoint(0);
											XYZ xyz2 = grid.Curve.GetEndPoint(1);
											xyz = transform3.OfPoint(xyz);
											xyz2 = transform3.OfPoint(xyz2);
											Line cvGrid = Line.CreateBound(xyz, xyz2);
											item = new DrawElement(grid, ElemType.eMultiSegGrid, true, cvGrid);
										}
										else
										{
											XYZ xyz3 = grid.Curve.GetEndPoint(0);
											XYZ xyz4 = grid.Curve.GetEndPoint(1);
											XYZ xyz5 = grid.Curve.Evaluate(0.5, true);
											xyz3 = transform3.OfPoint(xyz3);
											xyz4 = transform3.OfPoint(xyz4);
											xyz5 = transform3.OfPoint(xyz5);
											Arc cvGrid2 = Arc.Create(xyz3, xyz4, xyz5);
											item = new DrawElement(grid, ElemType.eMultiSegGrid, true, cvGrid2);
										}
										this.m_lstDrawElems.Add(item);
									}
								}
							}
						}
					}
					catch (Exception)
					{
					}
				}
			}
		}

		private void GetAllLevelInfo()
		{
            if ((int)this.m_uiDoc.ActiveView.ViewType != 3 && (int)this.m_uiDoc.ActiveView.ViewType != 117)
			{
				return;
			}
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc, this.m_uiDoc.ActiveView.Id);
			filteredElementCollector.OfClass(typeof(Level));
			foreach (Element element in filteredElementCollector)
			{
				Level level = element as Level;
				if (level != null)
				{
					DrawElement item = new DrawElement(level, ElemType.eLevel, false, null);
					this.m_lstDrawElems.Add(item);
				}
			}
		}

		private void GetAllLevelInfoInLinkDoc()
		{
            if ((int)this.m_uiDoc.ActiveView.ViewType != 3 && (int)this.m_uiDoc.ActiveView.ViewType != 117)
			{
				return;
			}
			foreach (RevitLinkInstance revitLinkInstance in this.m_lstLinkInst)
			{
				Document linkDocument = revitLinkInstance.GetLinkDocument();
				if (linkDocument != null)
				{
					try
					{
						FilteredElementCollector filteredElementCollector = new FilteredElementCollector(linkDocument, this.m_uiDoc.ActiveView.Id);
						filteredElementCollector.OfClass(typeof(Level));
						foreach (Element element in filteredElementCollector)
						{
							Level level = element as Level;
							if (level != null)
							{
								DrawElement item = new DrawElement(level, ElemType.eLevel, true, null);
								this.m_lstDrawElems.Add(item);
							}
						}
					}
					catch (Exception)
					{
					}
				}
			}
		}

		private void GetIntersectPtAndDirection()
		{
			foreach (ViewOutLineInfo viewOutLineInfo in this.m_lstViewOutLineInfo)
			{
				foreach (DrawElement drawElement in this.m_lstDrawElems)
				{
					Curve curve = null;
					if (drawElement.DrawElemType == ElemType.eGrid || drawElement.DrawElemType == ElemType.eMultiSegGrid)
					{
						Grid grid = drawElement.DrawElem as Grid;
						if (grid == null)
						{
							continue;
						}
						if (!drawElement.InLinkDoc)
						{
                            if (drawElement.DrawElemType == ElemType.eMultiSegGrid && ((int)this.m_doc.ActiveView.ViewType == 117 || (int)this.m_doc.ActiveView.ViewType == 3))
							{
								continue;
							}
							curve = RevitElementExtension.GetGridCurve(this.m_doc.ActiveView, grid);
						}
                        else if ((int)this.m_doc.ActiveView.ViewType != 117 && (int)this.m_doc.ActiveView.ViewType != 3)
						{
							curve = drawElement.LinkGridCurve;
						}
					}
					else if (drawElement.DrawElemType == ElemType.eLevel)
					{
						Level level = drawElement.DrawElem as Level;
						if (level == null)
						{
							continue;
						}
						curve = RevitElementExtension.GetLevelCurve(this.m_doc.ActiveView, level);
					}
					if (!(curve == null))
					{
						Curve curve2;
						if (curve is Arc)
						{
                            System.Drawing.Point point = this.Revit2Screen(curve.GetEndPoint(0));
                            System.Drawing.Point point2 = this.Revit2Screen(curve.GetEndPoint(1));
                            System.Drawing.Point point3 = this.Revit2Screen(curve.Evaluate(0.5, true));
							XYZ xyz = new XYZ((double)point.X, (double)point.Y, 0.0);
							XYZ xyz2 = new XYZ((double)point2.X, (double)point2.Y, 0.0);
							XYZ xyz3 = new XYZ((double)point3.X, (double)point3.Y, 0.0);
							curve2 = Arc.Create(xyz, xyz2, xyz3);
						}
						else
						{
                            System.Drawing.Point point4 = this.Revit2Screen(curve.GetEndPoint(0));
                            System.Drawing.Point point5 = this.Revit2Screen(curve.GetEndPoint(1));
							XYZ xyz4 = new XYZ((double)point4.X, (double)point4.Y, 0.0);
							XYZ xyz5 = new XYZ((double)point5.X, (double)point5.Y, 0.0);
							curve2 = Line.CreateBound(xyz4, xyz5);
						}
						IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
						SetComparisonResult setComparisonResult = viewOutLineInfo.ViewOutLine.Intersect(curve2, out intersectionResultArray);
						if (setComparisonResult == SetComparisonResult.Overlap && intersectionResultArray != null && intersectionResultArray.Size > 0)
						{
							for (int i = 0; i < intersectionResultArray.Size; i++)
							{
								GridNumShowInfo gridNumShowInfo = new GridNumShowInfo();
                                gridNumShowInfo.IntersectPoint = intersectionResultArray.get_Item(i).XYZPoint;
								gridNumShowInfo.OutlineSide = viewOutLineInfo.OutlineSide;
								gridNumShowInfo.ElemText = drawElement.DrawElem.Name;
								gridNumShowInfo.ElemClass = drawElement.DrawElemType;
								this.m_lstGridNumShowInfo.Add(gridNumShowInfo);
							}
						}
					}
				}
			}
		}

		public void TranformIntersectPt(IntPtr hFormClient)
		{
			try
			{
				foreach (GridNumShowInfo gridNumShowInfo in this.m_lstGridNumShowInfo)
				{
					XYZ intersectPoint = gridNumShowInfo.IntersectPoint;
					if (intersectPoint != null)
					{
						XYZ xyz = null;
						XYZ xyz2 = null;
						switch (gridNumShowInfo.OutlineSide)
						{
						case OutLineSide.eUp:
							xyz2 = intersectPoint + XYZ.BasisY * 25.0;
							xyz = intersectPoint - XYZ.BasisX * 25.0;
							break;
						case OutLineSide.eLeft:
							xyz2 = intersectPoint + XYZ.BasisX * 5.0;
							xyz = intersectPoint - XYZ.BasisY * 25.0;
							break;
						case OutLineSide.eRight:
							xyz2 = intersectPoint - XYZ.BasisX * 5.0;
							xyz = intersectPoint - XYZ.BasisY * 25.0 - XYZ.BasisX * 52.0;
							break;
						case OutLineSide.eBottom:
							xyz2 = intersectPoint - XYZ.BasisY * 25.0;
							xyz = intersectPoint - XYZ.BasisY * 52.0 - XYZ.BasisX * 25.0;
							break;
						}
                        System.Drawing.Point cirlLocation = new System.Drawing.Point((int)xyz.X, (int)xyz.Y);
						GridNumberShowManager.ScreenToClient(hFormClient, ref cirlLocation);
						gridNumShowInfo.CirlLocation = cirlLocation;
                        System.Drawing.Point textLocation = new System.Drawing.Point((int)xyz2.X, (int)xyz2.Y);
						GridNumberShowManager.ScreenToClient(hFormClient, ref textLocation);
						gridNumShowInfo.TextLocation = textLocation;
					}
				}
			}
			catch
			{
			}
		}

		[DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ScreenToClient(IntPtr hWnd, ref System.Drawing.Point pt);

        public System.Drawing.Point Revit2Screen(XYZ point)
		{
			try
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				RevitViewExtension.GetRevitWndRectangle(this.m_uiView, ref num, ref num2, ref num3, ref num4);
				Transform inverse = this.m_uiDoc.ActiveView.CropBox.Transform.Inverse;
				IList<XYZ> zoomCorners = this.m_uiView.GetZoomCorners();
				XYZ xyz = inverse.OfPoint(point);
				XYZ xyz2 = inverse.OfPoint(zoomCorners[0]);
				XYZ xyz3 = inverse.OfPoint(zoomCorners[1]);
				double num5 = (double)(num3 - num) / (xyz3.X - xyz2.X);
				int x = num + (int)((xyz.X - xyz2.X) * num5);
				int y = num2 + (int)((xyz3.Y - xyz.Y) * num5);
				return new System.Drawing.Point(x, y);
			}
			catch
			{
			}
            return System.Drawing.Point.Empty;
		}

		private const int GRIDNUM_RADIUS = 25;

		private const int GRIDNUM_OFFSET = 2;

		private const int GRIDNUM_TEXT = 5;

		public List<GridNumShowInfo> m_lstGridNumShowInfo = new List<GridNumShowInfo>();

		public bool m_bShowLink;

		private List<RevitLinkInstance> m_lstLinkInst = new List<RevitLinkInstance>();

		private List<ViewOutLineInfo> m_lstViewOutLineInfo = new List<ViewOutLineInfo>();

		private List<DrawElement> m_lstDrawElems = new List<DrawElement>();

		private UIDocument m_uiDoc;

		private Document m_doc;

		private UIView m_uiView;

		private int m_nLeft;

		private int m_nRight;

		private int m_nTop;

		private int m_nBottom;
	}
}
